package com.fary.aop.framework.autoproxy;

import com.fary.aop.Advisor;
import com.fary.beans.factory.BeanFactoryUtils;
import com.fary.beans.factory.config.ConfigurableListableBeanFactory;
import com.fary.util.Assert;
import com.sun.istack.internal.Nullable;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.ArrayList;
import java.util.List;

public class BeanFactoryAdvisorRetrievalHelper {

    private static final Log logger = LogFactory.getLog(BeanFactoryAdvisorRetrievalHelper.class);

    private final ConfigurableListableBeanFactory beanFactory;

    private volatile String[] cachedAdvisorBeanNames;


    /**
     * Create a new BeanFactoryAdvisorRetrievalHelper for the given BeanFactory.
     *
     * @param beanFactory the ListableBeanFactory to scan
     */
    public BeanFactoryAdvisorRetrievalHelper(ConfigurableListableBeanFactory beanFactory) {
        Assert.notNull(beanFactory, "ListableBeanFactory must not be null");
        this.beanFactory = beanFactory;
    }


    /**
     * Find all eligible Advisor beans in the current bean factory,
     * ignoring FactoryBeans and excluding beans that are currently in creation.
     * 忽略 FactoryBeans 并排除当前正在创建的 bean。
     */
    public List<Advisor> findAdvisorBeans() {
        // 从缓存中获取 advisorNames。因为每个Bean创建的时候都会进行一次获取，所以对增强的缓存是必须的
        String[] advisorNames = this.cachedAdvisorBeanNames;
        // 如果为null，表示没有缓存
        if (advisorNames == null) {
            // 注释： 不要在这里初始化FactoryBeans：我们需要保留所有未初始化的常规bean，以使自动代理创建者对其应用！个人理解是防止有的FactoryBean可能会被增强代理，而在这里初始化，则会没有办法进行代理
            // 从 Spring 中获取 Advisor 类型的 beanname 。这里获取到的一般都是硬编码注入的 Advisors
            advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Advisor.class, true, false);
            // 赋值给cachedAdvisorBeanNames，缓存起来，下次直接从缓存获取
            this.cachedAdvisorBeanNames = advisorNames;
        }
        // 如果没有获取到 Advisors ，直接返回
        if (advisorNames.length == 0) {
            return new ArrayList<>();
        }

        // 到这一步必定有Advisors ，我们需要通过name来获取到bean的实例
        List<Advisor> advisors = new ArrayList<>();
        for (String name : advisorNames) {
            // 当前Bean 是否合格，这里调用的是 AbstractAdvisorAutoProxyCreator#isEligibleAdvisorBean 直接返回true，供子类扩展。
            if (isEligibleBean(name)) {
                // 如果 name 指向的 bean 正在创建中则跳过
                if (this.beanFactory.isCurrentlyInCreation(name)) {
                    if (logger.isTraceEnabled()) {
                        logger.trace("Skipping currently created advisor '" + name + "'");
                    }
                } else {
                    try {
                        // 否则从容器中根据name 和 类型获取到 Advisor 实例，添加到 advisors 集合中
                        advisors.add(this.beanFactory.getBean(name, Advisor.class));
                    } catch (Exception ex) {
                        throw ex;
                    }
                }
            }
        }
        return advisors;
    }

    /**
     * Determine whether the aspect bean with the given name is eligible.
     * <p>The default implementation always returns {@code true}.
     *
     * @param beanName the name of the aspect bean
     * @return whether the bean is eligible
     */
    protected boolean isEligibleBean(String beanName) {
        return true;
    }

}